/**
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You under the Apache License, Version 2.0
 *  (the "License"); you may not use this file except in compliance with
 *  the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package org.apache.aries.samples.ariestrader.web;

import javax.servlet.*;
import javax.servlet.http.*;

import org.apache.aries.samples.ariestrader.api.persistence.*;
import org.apache.aries.samples.ariestrader.util.*;

import java.util.Collection;
import java.util.Iterator;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * TradeScenarioServlet emulates a population of web users by generating a specific Trade operation 
 * for a randomly chosen user on each access to the URL. Test this servlet by clicking Trade Scenario 
 * and hit "Reload" on your browser to step through a Trade Scenario. To benchmark using this URL aim 
 * your favorite web load generator (such as AKStress) at the Trade Scenario URL and fire away.
 */
public class TradeScenarioServlet extends HttpServlet {

   /**
	* Servlet initialization method.
	*/
	public void init(ServletConfig config) throws ServletException
	{
		super.init(config);
		java.util.Enumeration en = config.getInitParameterNames();
		while ( en.hasMoreElements() )
		{
			String parm = (String) en.nextElement();
			String value = config.getInitParameter(parm);
			TradeConfig.setConfigParam(parm, value);
		}
	}
	
   /**
	* Returns a string that contains information about TradeScenarioServlet
	*
	* @return The servlet information
	*/
	public java.lang.String getServletInfo()
	{
		return "TradeScenarioServlet emulates a population of web users";
	}	



   /**
	* Process incoming HTTP GET requests
	*
	* @param request Object that encapsulates the request to the servlet
	* @param response Object that encapsulates the response from the servlet
	*/
	public void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response)
		throws ServletException, IOException
	{
		performTask(request,response);
	}

   /**
	* Process incoming HTTP POST requests
	*
	* @param request Object that encapsulates the request to the servlet
	* @param response Object that encapsulates the response from the servlet
	*/
	public void doPost(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response)
		throws ServletException, IOException
	{
		performTask(request,response);
	}	

   /** 
	* Main service method for TradeScenarioServlet
	*
	* @param request Object that encapsulates the request to the servlet
	* @param response Object that encapsulates the response from the servlet
	*/    
	public void performTask(HttpServletRequest req, HttpServletResponse resp)
		throws ServletException, IOException {

		// Scenario generator for Trade2
		char action = ' ';
		String userID = null;

		// String to create full dispatch path to TradeAppServlet w/ request Parameters
		String dispPath = null; // Dispatch Path to TradeAppServlet

		String scenarioAction = (String) req.getParameter("action");
		if ((scenarioAction != null) && (scenarioAction.length() >= 1))
		{
			action = scenarioAction.charAt(0);
			if (action == 'n')
			{ //null;
				try
				{
					resp.setContentType("text/html");
					PrintWriter out = new PrintWriter(resp.getOutputStream());
					out.println("<HTML><HEAD>TradeScenarioServlet</HEAD><BODY>Hello</BODY></HTML>"); 
					out.close();
					return;
	
				}
				catch (Exception e)
				{
					Log.error(
						"trade_client.TradeScenarioServlet.service(...)" + 
						"error creating printwriter from responce.getOutputStream", e);
						
					resp.sendError(
							500, 
						"trade_client.TradeScenarioServlet.service(...): erorr creating and writing to PrintStream created from response.getOutputStream()"); 
				} //end of catch
	
			} //end of action=='n'
		}


		ServletContext ctx = null;
		HttpSession session = null;
		try
		{
			ctx = getServletConfig().getServletContext();
			// These operations require the user to be logged in. Verify the user and if not logged in
			// change the operation to a login
			session = req.getSession(true);
			userID = (String) session.getAttribute("uidBean");
		}
		catch (Exception e)
		{
			Log.error(
				"trade_client.TradeScenarioServlet.service(...): performing " + scenarioAction +
				"error getting ServletContext,HttpSession, or UserID from session" +
				"will make scenarioAction a login and try to recover from there", e);
			userID = null;
			action = 'l';
		}

		if (userID == null)
		{
			action = 'l'; // change to login
			TradeConfig.incrementScenarioCount();
		}
		else if (action == ' ') {
			//action is not specified perform a random operation according to current mix
			// Tell getScenarioAction if we are an original user or a registered user 
			// -- sellDeficits should only be compensated for with original users.
			action = TradeConfig.getScenarioAction(
				userID.startsWith(TradeConfig.newUserPrefix));
		}	
		switch (action)
			{

				case 'q' : //quote 
					dispPath = tasPathPrefix + "quotes&symbols=" + TradeConfig.rndSymbols();
					ctx.getRequestDispatcher(dispPath).include(req, resp);
					break;
				case 'a' : //account
					dispPath = tasPathPrefix + "account";
					ctx.getRequestDispatcher(dispPath).include(req, resp);
					break;
				case 'u' : //update account profile
					dispPath = tasPathPrefix + "account";
					ctx.getRequestDispatcher(dispPath).include(req, resp);

					String fullName = "rnd" + System.currentTimeMillis();
					String address = "rndAddress";
					String   password = "xxx";
					String email = "rndEmail";
					String creditcard = "rndCC";
					dispPath = tasPathPrefix + "update_profile&fullname=" + fullName + 
						"&password=" + password + "&cpassword=" + password + 					
						"&address=" + address +	"&email=" + email + 
						"&creditcard=" +  creditcard;
					ctx.getRequestDispatcher(dispPath).include(req, resp);
					break;
				case 'h' : //home
					dispPath = tasPathPrefix + "home";
					ctx.getRequestDispatcher(dispPath).include(req, resp);
					break;
				case 'l' : //login
					userID = TradeConfig.getUserID();
					String password2 = "xxx";
					dispPath = tasPathPrefix + "login&inScenario=true&uid=" + userID + "&passwd=" + password2;
					ctx.getRequestDispatcher(dispPath).include(req, resp);
						
					// login is successful if the userID is written to the HTTP session
					if (session.getAttribute("uidBean") == null) {
						System.out.println("TradeScenario login failed. Reset DB between runs");
					} 
					break;
				case 'o' : //logout
					dispPath = tasPathPrefix + "logout";
					ctx.getRequestDispatcher(dispPath).include(req, resp);
					break;
				case 'p' : //portfolio
					dispPath = tasPathPrefix + "portfolio";
					ctx.getRequestDispatcher(dispPath).include(req, resp);
					break;
				case 'r' : //register
					//Logout the current user to become a new user
					// see note in TradeServletAction
					req.setAttribute("TSS-RecreateSessionInLogout", Boolean.TRUE);
					dispPath = tasPathPrefix + "logout";
					ctx.getRequestDispatcher(dispPath).include(req, resp);

					userID = TradeConfig.rndNewUserID();
					String passwd = "yyy";
					fullName = TradeConfig.rndFullName();
					creditcard = TradeConfig.rndCreditCard();
					String money = TradeConfig.rndBalance();
					email = TradeConfig.rndEmail(userID);
					String smail = TradeConfig.rndAddress();
					dispPath = tasPathPrefix + "register&Full Name=" + fullName + "&snail mail=" + smail +
						"&email=" + email + "&user id=" + userID + "&passwd=" + passwd + 
						"&confirm passwd=" + passwd + "&money=" + money + 
						"&Credit Card Number=" + creditcard;
					ctx.getRequestDispatcher(dispPath).include(req, resp);
					break;
				case 's' : //sell
					dispPath = tasPathPrefix + "portfolioNoEdge";
					ctx.getRequestDispatcher(dispPath).include(req, resp);

					Collection holdings = (Collection) req.getAttribute("holdingDataBeans");
					int numHoldings = holdings.size();
					if (numHoldings > 0)
					{
						//sell first available security out of holding 
						
						Iterator it = holdings.iterator();
						boolean foundHoldingToSell = false;
						while (it.hasNext()) 
						{
							HoldingDataBean holdingData = (HoldingDataBean) it.next();
							if ( !(holdingData.getPurchaseDate().equals(new java.util.Date(0)))  )
							{
								Integer holdingID = holdingData.getHoldingID();

								dispPath = tasPathPrefix + "sell&holdingID="+holdingID;
								ctx.getRequestDispatcher(dispPath).include(req, resp);
								foundHoldingToSell = true;
								break;	
							}
						}
						if (foundHoldingToSell) break;
						if (Log.doTrace())
							Log.trace("TradeScenario: No holding to sell -switch to buy -- userID = " + userID + "  Collection count = " + numHoldings);		

					}
					// At this point: A TradeScenario Sell was requested with No Stocks in Portfolio
					// This can happen when a new registered user happens to request a sell before a buy
					// In this case, fall through and perform a buy instead

					/* Trade 2.037: Added sell_deficit counter to maintain correct buy/sell mix.
					 * When a users portfolio is reduced to 0 holdings, a buy is requested instead of a sell.
					 * This throws off the buy/sell mix by 1. This results in unwanted holding table growth
					 * To fix this we increment a sell deficit counter to maintain the correct ratio in getScenarioAction
					 * The 'z' action from getScenario denotes that this is a sell action that was switched from a buy
					 * to reduce a sellDeficit
					 */
					if (userID.startsWith(TradeConfig.newUserPrefix) == false)
					{
						TradeConfig.incrementSellDeficit();
					}
				case 'b' : //buy
					String symbol = TradeConfig.rndSymbol();
					String amount = TradeConfig.rndQuantity() + "";

					dispPath = tasPathPrefix + "quotes&symbols=" + symbol;
					ctx.getRequestDispatcher(dispPath).include(req, resp);

					dispPath = tasPathPrefix + "buy&quantity=" + amount + "&symbol=" + symbol;
					ctx.getRequestDispatcher(dispPath).include(req, resp);
					break;
			} //end of switch statement 
	}

	// URL Path Prefix for dispatching to TradeAppServlet
	private final static String tasPathPrefix = "/app?action=";

}
